LoginSignup
daikikatsuragawa
@daikikatsuragawa

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

GitHubのリポジトリの40,000件を超えるStarの付与履歴を全て取得したい

解決したいこと

GitHubの特定のリポジトリのStarの付与履歴を全て取得したいと考えています。そこで、GitHubのREST APIを使い、以下のドキュメントを参考に取得を試みました。

ドキュメントからは把握できず、挙動からの推測ではありますが、取得可能なStarの付与履歴は40,000件までのようです。そこで、40,000件を超えるStarの付与履歴を全て取得する方法について相談させていただきたいです。また、GitHubのREST APIによって、取得可能なStarの付与履歴が40,000件までという説明があれば、教えていただきたいです。

発生している問題・エラー

Starの付与履歴の取得スクリプト

import requests

# 対象リポジトリとREST API エンドポイント
# 参考:https://docs.github.com/ja/rest/activity/starring
owner = "pandas-dev"
repo = "pandas"
url = f"https://api.github.com/repos/{owner}/{repo}/stargazers"

# personal access token
# 参考:https://docs.github.com/ja/authentication/keeping-your-account-and-data-secure/managing-your-personal-access-tokens
token = "XXXXXXXXXX"

headers = {
    "Accept": "application/vnd.github.v3.star+json",
    "Authorization": f"token {token}",
}

params = {"per_page": 100, "page": 1}

stargazers = []

while True:
    response = requests.get(url, params=params, headers=headers)
    stargazers += response.json()

    # 次のページが存在する場合、パラメータを更新
    if "next" in response.links.keys():
        params["page"] += 1
    else:
        break

len(stargazers)
取得可能なStarの付与履歴の件数
40000

上記は以下のリポジトリについてのStarの付与履歴ですが、この件数に対して実際のStar数は42k(約42,000)件であり、不足していることが推測されます。

0

1Answer

API仕様には特に上限についての記述は見受けられませんでした。

response.linksに"last"が含まれていた時に、そのpage番号が想定と合っているかを確認してみてはいかがでしょうか。
また、stargazer[]にjsonを追加する時、別途整数値も同時にカウントアップさせて、len()の結果と齟齬がないか突き合わせてみてはいかがでしょう。

1

Comments

  1. あと、40kよりはるかに大きいレポジトリに対してはどのような値になるでしょうか。

    こちらは150kほどあります。
    不足具合によっては、stargazers[]がパンクしている可能性も考えられますね。

  2. 立て続けにすみません。
    whileループで連続してリクエストしているので、レート制限に引っかかってる可能性もありますね。

  3. @iiokazuya
    コメントいただき、ありがとうございます🙇

    response.linksに"last"が含まれていた時に、そのpage番号が想定と合っているかを確認してみてはいかがでしょうか。

    "last"が含まれるresponse.linksの"last"の内容を確認すると以下となります。

    # 省略
    params = {"per_page": 100, "page": 1}
    response = requests.get(url, params=params, headers=headers)
    response.links["last"]
    
    {'url': 'https://api.github.com/repositories/858127/stargazers?per_page=100&page=400',
     'rel': 'last'}
    

    URLクエリパラメータが?per_page=100&page=400となっていて、そもそも取得可能なStarの付与履歴は40,000件(100×400)ということになりそうですね…やはりGitHubのREST APIの仕様(限界)のような気もしてきました。

    また、stargazer[]にjsonを追加する時、別途整数値も同時にカウントアップさせて、len()の結果と齟齬がないか突き合わせてみてはいかがでしょう。

    こちらは、一致するため、取得可能なStarの付与履歴は40,000件という状況下では齟齬のない結果となっています。

    # 省略
    stargazers = []
    count = 0
    
    while True:
        response = requests.get(url, params=params, headers=headers)
        stargazers += response.json()
        count =+ 1
    
        # 次のページが存在するか否かを確認
        if "next" in response.links.keys():
            params["page"] += 1
        else:
            break
    
    len(stargazers) == count * 100
    
    True
    

    あと、40kよりはるかに大きいレポジトリに対してはどのような値になるでしょうか。
    https://github.com/microsoft/vscode
    こちらは150kほどあります。
    不足具合によっては、stargazers[]がパンクしている可能性も考えられますね。

    こちらも同様に、取得可能なStarの付与履歴は40,000件でした。

    立て続けにすみません。
    whileループで連続してリクエストしているので、レート制限に引っかかってる可能性もありますね。

    タイミングを空けて再実行しても同じなので、これは問題なさそうです。

  4. なるほど、どうも40,000件というのが、何か定められたもののようですね。
    GitHubのデータベースをパンクさせないように、リポジトリごとに40,000件以前の履歴は捨ててる可能性もありますね。(件数だけは記憶している)

  5. なるほど、どうも40,000件というのが、何か定められたもののようですね。

    おそらくそうだと思っています。

    GitHubのデータベースをパンクさせないように、リポジトリごとに40,000件以前の履歴は捨ててる可能性もありますね。(件数だけは記憶している)

    参考までにですが、「4,0000件以降の履歴を取得できない」が正しそうです。正確には以下だけで断定はできないのですが、ここ取得できた履歴の最新の日付が半年ほど前のもので、この規模のリポジトリのStarが半年ほどつかない可能性は低そうで、最古〜4,0000件までの履歴を取得しているようです。

    # 省略
    max([stargazer["starred_at"] for stargazer in stargazers])
    
    2023-11-15T17:18:58Z
    

    参考までに、他のツール(Webアプリケーション)を確認してみたところ、この半年でもStarは追加されていそうです。

Your answer might help someone💌